﻿using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Media;
using System.Xml;
using SHomeWorkshop.LunarPresentation.Interfaces;

namespace SHomeWorkshop.LunarPresentation.Expressions
{
    public class RichText : Expression, IAutoWrap
    {
        public RichText(SubPanel rootPanel, SubPanel parentPanel, Editor editor)
            : base(rootPanel, parentPanel, editor)
        {
            //textBlock = new TextBlock() { TextWrapping = TextWrapping.Wrap };
            //textBlock.PreviewMouseDown += new System.Windows.Input.MouseButtonEventHandler(textBlock_PreviewMouseDown);
            //textBlock.Foreground = ExForeground;
            //this.mainBorder.Child = textBlock;

            //textBlock.MouseLeftButtonDown +=
            //    new System.Windows.Input.MouseButtonEventHandler(textBlock_MouseLeftButtonDown);
            //textBlock.MouseLeftButtonUp +=
            //    new System.Windows.Input.MouseButtonEventHandler(textBlock_MouseLeftButtonUp);
            //textBlock.MouseRightButtonDown += new System.Windows.Input.MouseButtonEventHandler(textBlock_MouseRightButtonDown);

            //textBlock.MouseEnter += new System.Windows.Input.MouseEventHandler(textBlock_MouseEnter);
            //textBlock.MouseLeave += new System.Windows.Input.MouseEventHandler(textBlock_MouseLeave);

            //2011年11月26日，改支持富文本块内部右对齐。

            textPanel = new StackPanel();
            this.mainBorder.Child = textPanel;

            #region 绑定最大宽度。
            MultiBinding maxWidthBinding = new MultiBinding();

            Binding exFontSizeBinding = new Binding("ExFontSize");
            exFontSizeBinding.Source = editor;

            Binding wndWidthBinding = new Binding("ActualWidth");
            wndWidthBinding.Source = editor.BaseScrolledViewer;

            Binding indentBinding = new Binding("Indent");
            indentBinding.Source = this;

            Binding docAutoWrapBinding = new Binding("AutoWrap");
            docAutoWrapBinding.Source = editor;

            Binding selfAutoWrapBinding = new Binding("AutoWrap");
            selfAutoWrapBinding.Source = this;

            Binding maxTextWidthBinding = new Binding("MaxTextWidth");
            maxTextWidthBinding.Source = editor;

            maxWidthBinding.Bindings.Add(exFontSizeBinding);
            maxWidthBinding.Bindings.Add(wndWidthBinding);
            maxWidthBinding.Bindings.Add(indentBinding);
            maxWidthBinding.Bindings.Add(docAutoWrapBinding);
            maxWidthBinding.Bindings.Add(selfAutoWrapBinding);
            maxWidthBinding.Bindings.Add(maxTextWidthBinding);

            maxWidthBinding.Converter = Globals.maxWidthConverter;
            maxWidthBinding.ConverterParameter = this;

            BindingOperations.SetBinding(this, MaxWidthProperty, maxWidthBinding);
            #endregion

            this.chineseName = "富文本块";
        }

        void textBlock_PreviewMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (e.ClickCount == 2)
            {
                Commands.Command.EditRichText(this);
            }
        }

        void textBlock_MouseRightButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            this.Editor.SelectedExpression = this;
            e.Handled = true;
        }

        void textBlock_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
        {
            (sender as TextBlock).Background = Brushes.Transparent;
            mainBorder.Background = ExBackground;
            SelectAdorner.InvalidateVisual();
        }

        void textBlock_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
        {
            (sender as TextBlock).Background = Globals.baseActiveBackGround;
            SelectAdorner.InvalidateVisual();
        }

        /// <summary>
        /// 实现拖放。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void textBlock_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            Globals.DropExpression(this);
        }

        void textBlock_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            this.Editor.SelectedExpression = this;

            //准备拖动公式。
            Globals.dragSourceExpression = this;
            e.Handled = true;
        }

        private StackPanel textPanel;

        public StackPanel TextPanel
        {
            get { return textPanel; }
        }

        //private TextBlock textBlock;

        //public TextBlock TextBlock
        //{
        //    get { return textBlock; }
        //}

        public override Brush ExForeground
        {
            get
            {
                return base.ExForeground;
            }
            set
            {
                UpdateExForegroundWithoutXmlChanging(value);
                UpdateExForegroundToXmlData(value);
                Editor.IsModified = true;
            }
        }

        public override void UpdateExForegroundWithoutXmlChanging(Brush value)
        {
            base.UpdateExForegroundWithoutXmlChanging(value);

            base.exForeground = value;

            foreach (UIElement ue in textPanel.Children)
            {
                TextBlock tb = ue as TextBlock;
                if (tb != null)
                {
                    tb.Foreground = value;
                }
            }
            //this.textBlock.Foreground = value;
        }

        protected override void BuildChildren()
        {
            base.BuildChildren();

            if (this.XmlData == null) return;

            XmlAttribute attrAutoWrap = this.XmlData.GetAttribute("AutoWrap");
            if (attrAutoWrap != null)
            {
                try
                {
                    this.AutoWrap = (AutoWrapType)Enum.Parse(typeof(AutoWrapType), attrAutoWrap.Value);
                }
                catch (Exception ex)
                {
                    Dialogs.LunarMsgBox.MsgBoxShow(
                        Globals.appName,
                        "意外错误，文本块读取到的“自动折行”值非法。",
                        "异常信息如下：\r\n" + ex.Message,
                        ex.StackTrace, MessageBoxButton.OK, MessageBoxImage.Warning);
                    return;
                }
            }

            UpdateTextBlockFromXmlData();
        }

        /// <summary>
        /// 只用于UpdateTextBlockFromXmlData()方法内部。
        /// </summary>
        /// <returns></returns>
        private TextBlock NewTextBlock()
        {
            TextBlock textBlock = new TextBlock() { TextWrapping = TextWrapping.Wrap };
            textBlock.PreviewMouseDown += new System.Windows.Input.MouseButtonEventHandler(textBlock_PreviewMouseDown);
            textBlock.Foreground = ExForeground;
            textBlock.MouseLeftButtonDown +=
                new System.Windows.Input.MouseButtonEventHandler(textBlock_MouseLeftButtonDown);
            textBlock.MouseLeftButtonUp +=
                new System.Windows.Input.MouseButtonEventHandler(textBlock_MouseLeftButtonUp);
            textBlock.MouseRightButtonDown += new System.Windows.Input.MouseButtonEventHandler(textBlock_MouseRightButtonDown);

            textBlock.MouseEnter += new System.Windows.Input.MouseEventHandler(textBlock_MouseEnter);
            textBlock.MouseLeave += new System.Windows.Input.MouseEventHandler(textBlock_MouseLeave);
            return textBlock;
        }

        /// <summary>
        /// 根据XmlData来生成TextBlock的内容。
        /// </summary>
        /// <param name="xmlData">Xml数据。</param>
        /// <param name="textBlock">文本块。</param>
        /// <param name="ex">文本块所在的富文本块（公式）。</param>
        public void UpdateTextBlockFromXmlData()
        {
            if (this.XmlData == null || textPanel == null) return;

            this.textPanel.Children.Clear();

            XmlNodeList nodes = this.XmlData.SelectNodes("Text");
            if (nodes == null || nodes.Count <= 0)
            {
                this.textPanel.Children.Add(new TextBlock() { Text = "..富文本块.." });
                return;
            }

            //每碰到一个<Text />才会新建一个。
            TextBlock textBlock = NewTextBlock();
            this.textPanel.Children.Add(textBlock);

            foreach (XmlNode node in nodes)
            {
                if (node.InnerText == null || node.InnerText.Length == 0)
                {
                    //textBlock.Inlines.Add(new LineBreak());
                    //指<Text />这样的空节点，表示换行（分段）。
                    textBlock = NewTextBlock();
                    this.textPanel.Children.Add(textBlock);
                    continue;
                }

                Span span = new Span();
                span.Inlines.Add(new Run(Dialogs.RichTextEditor.RestoreXmlChars(node.InnerXml)));

                //取文本特性
                XmlAttribute attrForeground = node.GetAttribute("Foreground");
                if (attrForeground != null)
                {
                    Brush foreground = ColorPicker.GetBrushByName(attrForeground.Value);
                    if (foreground != null)
                        span.Foreground = foreground;
                }

                XmlAttribute attrBackground = node.GetAttribute("Background");
                if (attrBackground != null)
                {
                    Brush background = ColorPicker.GetBrushByName(attrBackground.Value);
                    if (background != null)
                        span.Background = background;
                }
                else
                {
                    span.Background = Brushes.Transparent;
                }

                XmlAttribute attrFontWeight = node.GetAttribute("FontWeight");
                if (attrFontWeight != null && attrFontWeight.Value == "Bold")
                {
                    span.FontWeight = FontWeights.Bold;
                }

                XmlAttribute attrFontStyle = node.GetAttribute("FontStyle");
                if (attrFontStyle != null && attrFontStyle.Value == "Italic")
                {
                    span.FontStyle = FontStyles.Italic;
                }

                XmlAttribute attrUnderLine = node.GetAttribute("UnderLine");
                if (attrUnderLine != null && attrUnderLine.Value == "True")
                {
                    span.TextDecorations.Add(TextDecorations.Underline);
                }

                XmlAttribute attrStrikeLine = node.GetAttribute("StrikeLine");
                if (attrStrikeLine != null && attrStrikeLine.Value == "True")
                {
                    span.TextDecorations.Add(TextDecorations.Strikethrough);
                }

                XmlAttribute attrFontName = node.GetAttribute("FontName");
                if (attrFontName != null)
                {
                    FontFamily fontFamily = new FontFamily(attrFontName.Value);
                    if (fontFamily != null)
                        span.FontFamily = fontFamily;
                }

                XmlAttribute attrBaseLineAlignment = node.GetAttribute("BaseLineAlignment");
                if (attrBaseLineAlignment != null)
                {
                    switch (attrBaseLineAlignment.Value)
                    {
                        case "Top":
                            {
                                span.BaselineAlignment = BaselineAlignment.Top;

                                Binding fontSizeBinding = new Binding("ExFontSize");
                                fontSizeBinding.Source = this.Editor;
                                fontSizeBinding.Converter = Globals.halfTextSizeConverter;

                                span.SetBinding(Span.FontSizeProperty, fontSizeBinding);
                                break;
                            }
                        case "Bottom":
                            {
                                span.BaselineAlignment = BaselineAlignment.Bottom;

                                Binding fontSizeBinding = new Binding("ExFontSize");
                                fontSizeBinding.Source = this.Editor;
                                fontSizeBinding.Converter = Globals.halfTextSizeConverter;

                                span.SetBinding(Span.FontSizeProperty, fontSizeBinding);
                                break;
                            }
                        default:
                            {
                                span.BaselineAlignment = BaselineAlignment.Baseline;
                                break;
                            }
                    }
                }

                XmlAttribute attrTextAlignment = node.GetAttribute("TextAlignment");
                if (attrTextAlignment != null)
                {
                    textBlock.TextAlignment = (TextAlignment)Enum.Parse(typeof(TextAlignment), attrTextAlignment.Value);
                }

                textBlock.Inlines.Add(span);
            }
        }

        #region “撤销”与“重做”。

        /// <summary>
        /// 这个方法是重头戏。必须列出本类型公式支持的所有“可修改”属性。
        /// </summary>
        /// <param name="propertyName"></param>
        /// <param name="value"></param>
        public override void SetProperty(string propertyName, string value)
        {
            base.SetProperty(propertyName, value);

            switch (propertyName)
            {
                case "XmlDataInnerXml":
                    {
                        this.XmlData.InnerXml = value;
                        UpdateTextBlockFromXmlData();
                        break;
                    }
                case "AutoWrap":
                    {
                        try
                        {
                            this.AutoWrap = (AutoWrapType)Enum.Parse(typeof(AutoWrapType), value);
                        }
                        catch (Exception ex)
                        {
                            Dialogs.LunarMsgBox.MsgBoxShow(
                                Globals.appName,
                                "意外错误，文本块读取到的“自动折行类型”值非法。",
                                "异常信息如下：\r\n" + ex.Message,
                                ex.StackTrace, MessageBoxButton.OK, MessageBoxImage.Warning);
                        }
                        break;
                    }
                //default:
                //    {
                //        MessageBox.Show("未找到属性：" + propertyName, Globals.appName,
                //            MessageBoxButton.OK, MessageBoxImage.Warning);
                //        break;
                //    }
                //TODO :完成BaseText的其它部分。
            }
        }
        #endregion

        private AutoWrapType autoWrap = AutoWrapType.FromDoc;

        public AutoWrapType AutoWrap
        {
            get
            {
                return autoWrap;
            }
            set
            {
                if (autoWrap != value)
                {
                    autoWrap = value;
                    this.XmlData.SetAttribute("AutoWrap", autoWrap.ToString());
                }

                switch (autoWrap)
                {
                    case AutoWrapType.FromDoc:
                        {
                            if (editor.AutoWrap)
                            {
                                foreach (UIElement ue in this.textPanel.Children)
                                {
                                    TextBlock tb = ue as TextBlock;
                                    if (tb != null)
                                    {
                                        tb.TextWrapping = TextWrapping.Wrap;
                                    }
                                }
                            }
                            else
                            {
                                foreach (UIElement ue in this.textPanel.Children)
                                {
                                    TextBlock tb = ue as TextBlock;
                                    if (tb != null)
                                    {
                                        tb.TextWrapping = TextWrapping.NoWrap;
                                    }
                                }
                            }

                            break;
                        }
                    case AutoWrapType.No:
                        {
                            foreach (UIElement ue in this.textPanel.Children)
                            {
                                TextBlock tb = ue as TextBlock;
                                if (tb != null)
                                {
                                    tb.TextWrapping = TextWrapping.NoWrap;
                                }
                            }

                            break;
                        }
                    case AutoWrapType.Wrap:
                        {
                            foreach (UIElement ue in this.textPanel.Children)
                            {
                                TextBlock tb = ue as TextBlock;
                                if (tb != null)
                                {
                                    tb.TextWrapping = TextWrapping.Wrap;
                                }
                            }

                            break;
                        }
                }

                //为便于绑定的刷新，这个放到外面。
                OnPropertyChanged(this, new PropertyChangedEventArgs("AutoWrap"));
            }
        }
    }
}
